﻿using System;
using Framework.Core.BootStrapper;
using Framework.Core.CommandLine;
using Framework.Core.Io;
using Rhino.Mocks;
using Xunit;

namespace Framework.Tests.Core.BootStrapper
{
    public class BootStrapperTest
    {
        // ReSharper disable ClassNeverInstantiated.Local
        class GoodPluginArgs : PluginCommandLineArgs
        {

        }

        class GoodPlugin : PluginBase<GoodPluginArgs>
        {
            public override int Execute(GoodPluginArgs args)
            {
                return 1;
            }
        }

        class BadPlugin : PluginBase<PluginCommandLineArgs>
        {
            public override int Execute(PluginCommandLineArgs args)
            {
                throw new Exception();
            }
        }
        // ReSharper restore ClassNeverInstantiated.Local

        private readonly MockRepository mockRepository;
        private readonly ICommandLineParser commandLineParserMock;
        private readonly IEnvironmentAdapter environmentAdapterMock;
        private readonly IBootStrapper bootStrapper;

        public BootStrapperTest()
        {
            mockRepository = new MockRepository();
            commandLineParserMock = mockRepository.StrictMock<ICommandLineParser>();
            environmentAdapterMock = mockRepository.StrictMock<IEnvironmentAdapter>();
            bootStrapper = new Framework.Core.BootStrapper.BootStrapper(commandLineParserMock, environmentAdapterMock);
        }

        [Fact]
        public void Should_have_constructor_without_parameters()
        {
            Assert.NotNull(new Framework.Core.BootStrapper.BootStrapper());
        }

        [Fact]
        public void Should_exit_negative_code_if_no_plugin_in_args()
        {
            var args = new[] { "" };

            commandLineParserMock.Expect(x => x.Parse<PluginCommandLineArgs>(args)).Throw(new ArgumentException());
            environmentAdapterMock.Expect(x => x.Exit(-1));

            mockRepository.ReplayAll();
            bootStrapper.Start(args);
            mockRepository.VerifyAll();
        }

        [Fact]
        public void Should_exit_negative_code_if_no_plugin_exists()
        {
            var args = new[] { @"/p:hello" };

            commandLineParserMock
                .Expect(x => x.Parse<PluginCommandLineArgs>(args))
                .Return(new PluginCommandLineArgs { Plugin = "hello" });

            environmentAdapterMock.Expect(x => x.Exit(-1));

            mockRepository.ReplayAll();
            bootStrapper.Start(args);
            mockRepository.VerifyAll();
        }

        [Fact]
        public void Should_run_plugin()
        {
            var args = new[] { @"/p:GoodPlugin" };

            commandLineParserMock
                .Expect(x => x.Parse<PluginCommandLineArgs>(args))
                .Return(new PluginCommandLineArgs { Plugin = "GoodPlugin" });

            environmentAdapterMock.Expect(x => x.Exit(1));

            mockRepository.ReplayAll();
            bootStrapper.Add<GoodPlugin>().Start(args);
            mockRepository.VerifyAll();

        }

        [Fact]
        public void Should_exit_with_negative_code_when_run_failing_plugin()
        {
            var args = new[] { @"/p:BadPlugin" };

            commandLineParserMock
                .Expect(x => x.Parse<PluginCommandLineArgs>(args))
                .Return(new PluginCommandLineArgs { Plugin = "BadPlugin" });

            environmentAdapterMock.Expect(x => x.Exit(-1));

            mockRepository.ReplayAll();
            bootStrapper.Add<BadPlugin>().Start(args);
            mockRepository.VerifyAll();

        }
    }
}
